<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>js 基础演示</title>
</head>

<body>

</body>
<script>
    const deepClone = (obj = {}) => {
        // 判断基本数据类型和null 直接返回
        if (typeof obj !== 'object' || obj == null) {
            return obj;
        }
        let result;
        if (obj instanceof Array) {
            result = [];
        } else {
            result = {};
        }
        for (let key in obj) {
            // 保证key不是原型属性
            if (obj.hasOwnProperty(key)) {
                // 递归调用  
                result[key] = deepClone(obj[key]);
            }
        }
        // 返回结果
        return result;
    }
    let obj1 = { age: 20, arr: [0, 2, 3] };
    let obj2 = deepClone(obj1);
    obj2.age = 23;
    obj2.arr[0] = "56"
    console.log(obj2.arr)
    // let obj1 = { age: 20 }
    // let obj2 = JSON.parse(JSON.stringify(obj1))

    const a = 100 + 10;
    const b = 100 + '10';
    const c = true + '10';
    console.log(a);//110
    console.log(b);//'10010'
    console.log(c);//'true10'

    100 == '100';//true
    0 == '' //true
    0 == false //true
    false == '' //true
    null == undefined //true

    console.log(10 && 0) //0
    console.log('' || 'abc'); //abc
    console.log(!window.abc); // true

    console.log([] instanceof Array)

    // 闭包-函数作为返回值
    function create() {
        const a = 100;
        return function () {
            console.log(a);
        }
    }
    const fn = create();
    const a = 200;
    fn();//答案：100

    // 闭包-函数作为参数
    function print(fn) {
        const a = 200;
        fn();
    }
    const a = 100;
    function fn() {
        console.log(a);
    }
    print(fn)//答案：100

    Function.prototype.bind1 = function () {
        // 将参数拆解为数据
        const args = Array.prototype.slice.call(arguments);//（ES5）
        // const args=Array.from(arguments);//（ES6）

        //获取this(数组的第一项)
        const t = args.shift();
        const self = this;
        // 返回一个函数
        return function () {
            return self.apply(t, args);
        }
    }
    


    // 图片链接
    const url = 'xxx.png';
    function loadImg(src) {
        const p = new Promise((resolve, reject) => {
            const img = document.createElement('img');
            img.onload = () => {
                resolve(img);
            }
            img.onerror = () => {
                const err = new Error(`图片加载失败 ${src}`);
                reject(err);
            }
            img.src = src;
        })
        return p;
    }
    loadImg(url).then(img => {
        // 执行业务
        console.log(img.width);
        return img
    }).then(img => {
        // 执行业务
        console.log(img.height);
    }).catch(err => {
        console.log(err)
    })

    // 下面打印顺序
    console.log(1)
    setTimeout(() => {
        console.log(2);
    }, 2000)
    console.log(3)
    setTimeout(() => {
        console.log(4)
    }, 0)
    console.log(5)
    // 打印顺序  1 3 5 4 2

    // 第一题
    Promise.resolve().then(() => {
        console.log(1);
    }).catch(() => {
        console.log(2);
    }).then(() => {
        console.log(3);
    })
    // 打印1  3

    // 第二题
    Promise.resolve().then(() => {
        console.log(1);
        throw new Error('error1')
    }).catch(() => {//resolve
        console.log(2);
    }).then(() => {
        console.log(3);
    })//resolve
    // 打印1 2 3

    // 第三题
    Promise.resolve().then(() => {
        console.log(1);
        throw new Error('error1')
    }).catch(() => {//resolve
        console.log(2);
    }).catch(() => {
        console.log(3);
    })//resolve
    // 打印1 2 

    // 下面代码的打印顺序
    async function async1() {
        console.log('async1 start');//2
        await async2();
        // callback 微任务
        console.log('async1 end');//6
    }
    async function async2() {
        console.log('async2');//3
    }

    console.log('script start');//1

    setTimeout(() => {//宏任务
        console.log('setTimeout');//8
    }, 0)

    async1();

    new Promise(function (resolve) {
        console.log('promise1');//4
        resolve();
    }).then(() => {
        // 微任务
        console.log('promise2');//7
    })
    console.log('script end');//5

    // 元素
    const div1 = document.getElementById('div1')
    // 新建节点
    const p1 = document.createElement('p');
    p1.innerHTML = 'this is p1';
    // 插入节点
    div1.appendChild(p1);
    // 移动节点
    div1.appendChild(p1);
    // 获取父元素
    console.log(p1.parentNode);
    // 获取子元素列表
    const childs = div1.childNodes
    // 删除元素
    div1.removeChild(p1)

    // 将频繁操作改为一次性操作
    const listNode = document.getElementById('list');
    // 创建一个文档片段，此时还没有插入DOM树中
    const frag = document.createDocumentFragment();
    // 执行插入
    for (let x = 0; x < 10; x++) {
        const li = document.createElement('li');
        li.innerHTML = "list item" + i;
        frag.appendChild(li);
    }
    // 都完成之后，再插入到DOM树中
    listNode.appendChild(frag);

    // get请求
    const xhr = XMLHttpRequest();
    xhr.open("GET", "/api", false);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                console.log(xhr.responseText);
            }
        }
    }
    // post请求
    const xhr = XMLHttpRequest();
    xhr.open("POST", "/api", false);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                console.log(xhr.responseText);
            }
        }
    }
    let postData = {};
    xhr.send(JSON.stringify(postData));

    // 封装ajax
    function ajax(url) {
        return new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if (xhr.status == 200) {
                        resolve(JSON.parse(xhr.responseText));
                    } else if (xhr.status == 404) {
                        reject(new Error("404 not found"));
                    }
                }
            }
        })
    }

    // 手写深度比较isEqual
    /* 判断是否为对象**/
    function isObject(obj) {
        return typeof obj === 'object' && obj !== null;
    }
    /* 判断全相等**/
    function isEqual(obj1, obj2) {
        if (!isObject(obj1) || !isObject(obj2)) {
            return obj1 === obj2;
        }
        if (obj1 === obj2) {
            return true;
        }
        const obj1Keys = Object.keys(obj1);
        const obj2Keys = Object.keys(obj2);
        if (obj1Keys.length !== obj2Keys.length) {
            return false;
        }
        for (let key in obj1) {
            const res = isEqual(obj1[key], obj2[key]);
            if (!res) {
                return false;
            }
        }
        return true;
    }

    // test
    let obj1 = {
        name: 'zhangsan',
        likes: {
            color: 'blue',
            fruit: 'apple',
        }
    }
    let obj2 = {
        name: 'zhangsan',
        likes: {
            color: 'blue',
            fruit: 'apple',
        }
    }
    console.log(isEqual(obj1, obj2));
    // 简便方法
    console.log(JSON.stringify(obj3) === JSON.stringify(obj4))

    // 手写数组去重
    function unique(arr){
        const res=[];
        arr.forEach(item => {
            if(res.indexOf(item)==-1){
                res.push(item);
            } 
        });
        return res;
    }











</script>




</html>